package touchercouler;

import java.awt.Point;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;

public class MoteurInference
{
	private Point   lastCoord;
	private ArrayList<Regle> regles;
	private ArrayList<Fait> baseDeFaits;
	private ArrayList<Point> coups;
	private int coordRetour[] = new int[2];
	private boolean termine = false;
	private boolean continu = false;
	private Etat derniereconclusion;
	
	public MoteurInference()
	{
		regles = new ArrayList<Regle>();
		
		//URL url = getClass().getResource("Battleship.rules");
		URL url = ClassLoader.getSystemResource("Battleship.rules");
		
		Path filePath = null;
		try {
			filePath = Paths.get(url.toURI());
		} catch (URISyntaxException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		try {
			Scanner fileScan = new Scanner(filePath);
			
			while (fileScan.hasNextLine())
			{
				Regle regle = new Regle();
				
				Scanner lineScan = new Scanner(fileScan.nextLine());
				lineScan.useDelimiter("=>");
				String conditions = lineScan.next();
				String conditionArray[] = conditions.split(",");
				
				regle.premisses = new Fait[conditionArray.length];
				int i = 0;
				
				for (String condition : conditionArray) {
					Scanner conditionScan = new Scanner(condition.trim());
					conditionScan.useDelimiter("\\(");
					String etat = conditionScan.next();
					char variable = conditionScan.next().charAt(0);
					
					Etat premisse = InterpretePremisse(etat);
					regle.premisses[i] = new Fait(premisse, variable);
					++i;
				}
				
				String conclusion = lineScan.next();
				conclusion = conclusion.trim();
				
				regle.conclusion = InterpretePremisse(conclusion);
				
				regles.add(regle);
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		baseDeFaits = new ArrayList<Fait>();
		coups = new ArrayList<Point>();
	}
	
	public boolean estSolution()
	{
		return true;
	}
	
	public void majBaseDeFait(char connaissances[][])
	{
		
		baseDeFaits.clear();
		if(derniereconclusion==Etat.ALEA){
			baseDeFaits.add(new Fait(Etat.AVANT_DERNIER_COUP, 'o'));
		}
		if(derniereconclusion==Etat.ROLLBACK){
			int x, y;
			
			x = coups.get(coups.size()-3).x;
			y = coups.get(coups.size()-3).y;
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP,connaissances[x][y]));
			baseDeFaits.add(new Fait(Etat.AVANT_DERNIER_COUP, 'o'));
		}
		
		if (coups.size() == 0)
		{
			
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP, 'o'));
			baseDeFaits.add(new Fait(Etat.AVANT_DERNIER_COUP, 'o'));
			
			return;
		}
		
		
		int x, y,x1,y1,x2,y2;
		
		x = coups.get(coups.size()-1).x;
		y = coups.get(coups.size()-1).y;
		baseDeFaits.add(new Fait(Etat.DERNIER_COUP, connaissances[x][y]));
		
		if (x > 0)
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_HAUT, connaissances[x-1][y]));
		else
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_HAUT, 'o'));
		
		if (x < 9)
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_BAS, connaissances[x+1][y]));
		else
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_BAS, 'o'));
		
		if (y > 0)
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_GAUCHE, connaissances[x][y-1]));
		else
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_GAUCHE, 'o'));
		
		if (y < 9)
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_DROITE, connaissances[x][y+1]));
		else
			baseDeFaits.add(new Fait(Etat.DERNIER_COUP_DROITE, 'o'));
		
		
		if (coups.size() == 1)
		{
			baseDeFaits.add(new Fait(Etat.AVANT_DERNIER_COUP, 'o'));
			return;
		}
		else{
		x = coups.get(coups.size()-2).x;
		y = coups.get(coups.size()-2).y;
		baseDeFaits.add(new Fait(Etat.AVANT_DERNIER_COUP, connaissances[x][y]));
		
		}
		
		x1 = coups.get(coups.size()-1).x;
		y1 = coups.get(coups.size()-1).y;
		x2 = coups.get(coups.size()-2).x;
		y2 = coups.get(coups.size()-2).y;
		if(continu==true){
			baseDeFaits.add(new Fait(Etat.CONTINU, connaissances[x2][y2]));
		}
		if( connaissances[x1][y1] != connaissances[x2][y2] && connaissances[x1][y1] != 'o' && connaissances[x2][y2] != 'o')
		{
			baseDeFaits.add(new Fait(Etat.BATEAU_DIFFERENT, connaissances[x1][y1]));
		}
		char lettresBateau[] = new char[] { 'f', 'g', 'h', 'i', 'j' };
		for (int i = 0; i < 5; ++i)
		{
			if (FenetreJeu.EstBateauCoule(i) == false)
				baseDeFaits.add(new Fait(Etat.BATEAU_PAS_COULE, lettresBateau[i]));
		}
		
		Point f, g, h, i, j;
		f = g = h = i = j = new Point(-1, -1);
		for (int k = 0; k < 10; ++k)
		{
			for (int l = 0; l < 10; ++l)
			{
				switch (connaissances[k][l]) {
				case 'f':
					if (f.x == -1)
						f = new Point(k, l);
					else
					{
						if (f.x == k)
							baseDeFaits.add(new Fait(Etat.BATEAU_VERTICAL, 'f'));
						else
							baseDeFaits.add(new Fait(Etat.BATEAU_HORIZONTAL, 'f'));
					}
					break;
				case 'g':
					if (g.x == -1)
						g = new Point(k, l);
					else
					{
						if (g.x == k)
							baseDeFaits.add(new Fait(Etat.BATEAU_VERTICAL, 'g'));
						else
							baseDeFaits.add(new Fait(Etat.BATEAU_HORIZONTAL, 'g'));
					}
					break;
				case 'h':
					if (h.x == -1)
						h = new Point(k, l);
					else
					{
						if (h.x == k)
							baseDeFaits.add(new Fait(Etat.BATEAU_VERTICAL, 'h'));
						else
							baseDeFaits.add(new Fait(Etat.BATEAU_HORIZONTAL, 'h'));
					}
					break;
				case 'i':
					if (i.x == -1)
						i = new Point(k, l);
					else
					{
						if (i.x == k)
							baseDeFaits.add(new Fait(Etat.BATEAU_VERTICAL, 'i'));
						else
							baseDeFaits.add(new Fait(Etat.BATEAU_HORIZONTAL, 'i'));
					}
					break;
				case 'j':
					if (j.x == -1)
						j = new Point(k, l);
					else
					{
						if (j.x == k)
							baseDeFaits.add(new Fait(Etat.BATEAU_VERTICAL, 'j'));
						else
							baseDeFaits.add(new Fait(Etat.BATEAU_HORIZONTAL, 'j'));
					}
					break;
				default:
					break;
				}
			}
		}
		
	}
	
	public int[] calculCoup(char connaissances[][])
	{
		majBaseDeFait(connaissances);
		termine = false;
		
		ArrayList<Regle> reglesNonMarquees = new ArrayList<Regle>();
		for (int i = 0; i < regles.size(); ++i){
			reglesNonMarquees.add(regles.get(i));
		}
			
		
		ArrayList<Regle> reglesAppliquer = new ArrayList<Regle>();
		ArrayList<Regle> reglesMarquees = new ArrayList<Regle>();
		
		while (!termine && !reglesNonMarquees.isEmpty())
		{
			
			
			for(int i=0; i<reglesNonMarquees.size();i++)
			 {	Regle regle=reglesNonMarquees.get(i);
				for (Fait fait : baseDeFaits) {
					if (regle.satisfaitCondition(fait)){
						reglesMarquees.add(regle);
						reglesNonMarquees.remove(regle);
						--i;
						
					break;
				}
					else
					{
						reglesNonMarquees.remove(regle);
						--i;
						break;
					}
				}
			}
			for (int i=0; i<reglesMarquees.size();i++) {
				Regle regle = reglesMarquees.get(i);
				if (regle.satisfaitConditions(baseDeFaits))
				{
					reglesAppliquer.add(regle);
					reglesMarquees.remove(regle);
					--i;
				}
			}
			
			Regle regleAppliquer=null;
			int nombrePremisses = 0;
			for (Regle regle : reglesAppliquer) {
				if (regle.premisses.length >= nombrePremisses)
				{
					nombrePremisses = regle.premisses.length;
					regleAppliquer  = regle;
				}
			}			
			// Appliquer regle
			AppliquerRegle(regleAppliquer.conclusion,connaissances);
			majBaseDeFait(connaissances);
			
		}
		coups.add(new Point(coordRetour[0],coordRetour[1]));
		return coordRetour;
	}
	
	public void AppliquerRegle(Etat conclusion, char connaissances[][])
	{
		
		switch (conclusion)
		{
		case DERNIER_COUP_BAS:
			derniereconclusion=Etat.DERNIER_COUP_BAS;
			coordRetour[0] = coups.get(coups.size()-1).x+1;
			coordRetour[1] = coups.get(coups.size()-1).y;
			termine = true;
			break;
		case DERNIER_COUP_DROITE:
			derniereconclusion=Etat.DERNIER_COUP_DROITE;
			coordRetour[0] = coups.get(coups.size()-1).x;
			coordRetour[1] = coups.get(coups.size()-1).y+1;
			termine = true;
			break;
		case DERNIER_COUP_GAUCHE:
			derniereconclusion=Etat.DERNIER_COUP_GAUCHE;
			coordRetour[0] = coups.get(coups.size()-1).x;
			coordRetour[1] = coups.get(coups.size()-1).y-1;
			termine = true;
			break;
		case DERNIER_COUP_HAUT:
			derniereconclusion=Etat.DERNIER_COUP_HAUT;
			coordRetour[0] = coups.get(coups.size()-1).x-1;
			coordRetour[1] = coups.get(coups.size()-1).y;
			termine = true;
			break;
		case ALEA:
			derniereconclusion=Etat.ALEA;
			coordRetour[0] = (int)(Math.random() * ((9) + 1));
			coordRetour[1] = (int)(Math.random() * ((9) + 1));
			termine = true;
			break;
		case CONTINU:
			continu = true;
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y<0 && coups.get(coups.size()-1).y>0){
			coordRetour[0] = coups.get(coups.size()-1).x;
			coordRetour[1] = coups.get(coups.size()-1).y - 1;
			termine = true;
			}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y>0 && coups.get(coups.size()-1).y<9){
				coordRetour[0] = coups.get(coups.size()-1).x;
				coordRetour[1] = coups.get(coups.size()-1).y + 1;
				termine = true;
				}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x<0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x>0){
				coordRetour[0] = coups.get(coups.size()-1).x - 1;
				coordRetour[1] = coups.get(coups.size()-1).y;
				termine = true;
				}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x>0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x<9){
				coordRetour[0] = coups.get(coups.size()-1).x + 1;
				coordRetour[1] = coups.get(coups.size()-1).y;
				termine = true;
				}
			break;
		case ROLLBACK:
			//derniereconclusion=Premisse.ROLLBACK;
			//coups.remove(coups.size()-1);
			//derniereconclusion=Premisse.ROLLBACK;
			//coups.remove(coups.size()-1);
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y<0 && coups.get(coups.size()-1).y<9){
				coordRetour[0] = coups.get(coups.size()-1).x;
				coordRetour[1] = coups.get(coups.size()-1).y + 1;
				termine = true;
			}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y>0 && coups.get(coups.size()-1).y>0){
				coordRetour[0] = coups.get(coups.size()-1).x;
				coordRetour[1] = coups.get(coups.size()-1).y - 1;
				termine = true;
			}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x<0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x<9){
				coordRetour[0] = coups.get(coups.size()-1).x + 1;
				coordRetour[1] = coups.get(coups.size()-1).y;
				termine = true;
			}
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x>0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x>0){
				coordRetour[0] = coups.get(coups.size()-1).x - 1;
				coordRetour[1] = coups.get(coups.size()-1).y;
				termine = true;
			}
			
			
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x!=0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y!=0){
				do{
					coordRetour[0] = (int)(Math.random() * ((9) + 1));
					coordRetour[1] = (int)(Math.random() * ((9) + 1));
					}while(connaissances[coordRetour[0]][coordRetour[1]]!='v');
				
			}
				
			break;
			
		case DEMITOUR:
			//derniereconclusion=Premisse.ROLLBACK;
			//coups.remove(coups.size()-1);
			//derniereconclusion=Premisse.ROLLBACK;
			//coups.remove(coups.size()-1);
			continu=false;
			if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y<0 && coups.get(coups.size()-1).y<9){
				coordRetour[0] = coups.get(coups.size()-1).x;
				coordRetour[1] = coups.get(coups.size()-1).y + 1;
				while(connaissances[coordRetour[0]][coordRetour[1]]!='v' && coordRetour[1]<9){
					coordRetour[1]++;
				}
				termine = true;
				}
				if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x==0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y>0 && coups.get(coups.size()-1).y>0){
					coordRetour[0] = coups.get(coups.size()-1).x;
					coordRetour[1] = coups.get(coups.size()-1).y - 1;
					while(connaissances[coordRetour[0]][coordRetour[1]]!='v' && coordRetour[1]>0){
						coordRetour[1]--;
					}
					termine = true;
					}
				if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x<0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x<9){
					coordRetour[0] = coups.get(coups.size()-1).x + 1;
					coordRetour[1] = coups.get(coups.size()-1).y;
					while(connaissances[coordRetour[0]][coordRetour[1]]!='v' && coordRetour[0]<9){
						coordRetour[0]++;
					}
					termine = true;
					}
				if(coups.get(coups.size()-1).x-coups.get(coups.size()-2).x>0 && coups.get(coups.size()-1).y-coups.get(coups.size()-2).y==0 && coups.get(coups.size()-1).x>0){
					coordRetour[0] = coups.get(coups.size()-1).x - 1;
					coordRetour[1] = coups.get(coups.size()-1).y;
					while(connaissances[coordRetour[0]][coordRetour[1]]!='v' && coordRetour[0]>0){
						coordRetour[0]--;
					}
					termine = true;
					}
				
				break;
		default:
			break;
		}
	}
	
	public Etat InterpretePremisse(String premisse)
	{
		Etat retour = null;
		switch (premisse)
		{
		case "DERNIER_COUP":
			retour = Etat.DERNIER_COUP;
			break;
		case "AVANT_DERNIER_COUP":
			retour = Etat.AVANT_DERNIER_COUP;
			break;
		case "DERNIER_COUP_DROITE":
			retour = Etat.DERNIER_COUP_DROITE;
			break;
		case "DERNIER_COUP_GAUCHE":
			retour = Etat.DERNIER_COUP_GAUCHE;
			break;
		case "DERNIER_COUP_HAUT":
			retour = Etat.DERNIER_COUP_HAUT;
			break;
		case "DERNIER_COUP_BAS":
			retour = Etat.DERNIER_COUP_BAS;
			break;
		case "ALEA":
			retour = Etat.ALEA;
			break;
		case "ROLLBACK":
			retour = Etat.ROLLBACK;
			break;
		case "BATEAU_VERTICAL":
			retour = Etat.BATEAU_VERTICAL;
			break;
		case "BATEAU_HORIZONTAL":
			retour = Etat.BATEAU_HORIZONTAL;
			break;
		case "BATEAU_PAS_COULE":
			retour = Etat.BATEAU_PAS_COULE;
			break;
		case "CONTINU":
			retour = Etat.CONTINU;
			break;
		case "BATEAU_DIFFERENT":
			retour = Etat.BATEAU_DIFFERENT;
			break;
		case "VOISIN_VISITES":
			retour = Etat.VOISIN_VISITES;
			break;
		case "DEMITOUR":
			retour = Etat.DEMITOUR;
			break;
		default:
				break;
		}
		return retour;
	}
	
}
